﻿using System;
using System.IO;
using Microsoft.Xna.Framework;

namespace ThreeDContentPipeline
{
    public class MD2Header
    {
        public readonly int ID;
        public readonly int Version;
        public readonly int SkinWidth;
        public readonly int SkinHeight;
        public readonly int FrameSize;
        public readonly int NumSkins;
        public readonly int NumXYZ;
        public readonly int NumST;
        public readonly int NumTris;
        public readonly int NumGLCmds;
        public readonly int NumFrames;
        public readonly int OffSkins;
        public readonly int OffST;
        public readonly int OffTris;
        public readonly int OffFrames;
        public readonly int OffGLCmds;
        public readonly int OffEnd;

        public MD2Header(BinaryReader reader)
        {
            ID = reader.ReadInt32();
            Version = reader.ReadInt32();
            SkinWidth = reader.ReadInt32();
            SkinHeight = reader.ReadInt32();
            FrameSize = reader.ReadInt32();
            NumSkins = reader.ReadInt32();
            NumXYZ = reader.ReadInt32();
            NumST = reader.ReadInt32();
            NumTris = reader.ReadInt32();
            NumGLCmds = reader.ReadInt32();
            NumFrames = reader.ReadInt32();
            OffSkins = reader.ReadInt32();
            OffST = reader.ReadInt32();
            OffTris = reader.ReadInt32();
            OffFrames = reader.ReadInt32();
            OffGLCmds = reader.ReadInt32();
            OffEnd = reader.ReadInt32();
        }
    }

    public class MD2Vertex
    {
        public readonly byte[] V;
        public readonly byte N;

        public MD2Vertex(BinaryReader reader)
        {
            V = reader.ReadBytes(3);
            N = reader.ReadByte();
        }
    }

    public class MD2TexCoord
    {
        public readonly short S;
        public readonly short T;

        public MD2TexCoord(BinaryReader reader)
        {
            S = reader.ReadInt16();
            T = reader.ReadInt16();
        }
    }

    public class MD2Triangle
    {
        public readonly ushort[] V;
        public readonly ushort[] T;

        public MD2Triangle(BinaryReader reader)
        {
            V = new ushort[] { reader.ReadUInt16(), reader.ReadUInt16(), reader.ReadUInt16() };
            T = new ushort[] { reader.ReadUInt16(), reader.ReadUInt16(), reader.ReadUInt16() };
        }
    }

    public class MD2Frame
    {
        public readonly Vector3 Scale;
        public readonly Vector3 Translate;
        public readonly MD2Vertex[] Vertices;

        public MD2Frame(MD2Header header, BinaryReader reader)
        {
            Scale = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
            Translate = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
            reader.BaseStream.Position += 16;
            Vertices = new MD2Vertex[header.NumXYZ];
            for (int i = 0; i != header.NumXYZ; i++)
            {
                Vertices[i] = new MD2Vertex(reader);
            }
        }
    }

    public class MD2File
    {
        public readonly MD2Header Header;
        public readonly MD2TexCoord[] TexCoords;
        public readonly MD2Triangle[] Triangles;
        public readonly MD2Frame[] Frames;

        public MD2File(string file)
        {
            BinaryReader reader = null;

            try
            {
                reader = new BinaryReader(new MemoryStream(File.ReadAllBytes(file)));

                Header = new MD2Header(reader);

                reader.BaseStream.Position = Header.OffST;
                TexCoords = new MD2TexCoord[Header.NumST];
                for (int i = 0; i != Header.NumST; i++)
                {
                    TexCoords[i] = new MD2TexCoord(reader);
                }

                reader.BaseStream.Position = Header.OffTris;
                Triangles = new MD2Triangle[Header.NumTris];
                for (int i = 0; i != Header.NumTris; i++)
                {
                    Triangles[i] = new MD2Triangle(reader);
                }

                Frames = new MD2Frame[Header.NumFrames];
                for (int i = 0; i != Header.NumFrames; i++)
                {
                    reader.BaseStream.Position = Header.OffFrames + i * Header.FrameSize;
                    Frames[i] = new MD2Frame(Header, reader);
                }
            }
            finally
            {
                if (reader != null)
                {
                    reader.Close();
                }
            }
        }
    }
}
